home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 52
/
Amiga Format AFCD52 (Issue 136, May 2000).iso
/
-serious-
/
programming
/
basic
/
udp_chat
/
udp_chatv2.7.asc
< prev
next >
Wrap
Text File
|
2000-02-23
|
78KB
|
2,082 lines
;
; UDP Chat code V2.7 16/1/2000
;
; This code sends and receives UDP data packets like a
; a simple IRC client, and checks wether they have arrived
; at their destination, and allows other copies of this
; program to log in to this one (can act as a server or client).
;
; Written by Anton Reinauer <anton@ww.co.nz>.
; GUI: Alvaro Thompson <alvaro@enterprise.net> - And awful hacks
; by me to his nice font sensitive code :-)
; - typical bloody games programmer ;-)
;
; Thanks to Paul Burkey for TCP_Funcs and to Dr. Ercole Spiteri
; for TCP-to-Blitz.
;
; ARexx portname: "UDP_Chat"
;
; Turn overflow errors off in Debugger options,
; and have amigalibs.res resident in compiler options.
WBStartup
NoCli
DEFTYPE .w
ResetTimer
;****************************************************************
;**************** UDP Stuff **************
;*********** Cut out all this and put it in your game **********
;****************************************************************
;**************** UDP Variables and Constants **************
hostname.s="localhost" ; "localhost" default destination host address
#NO_CONNECTION=1 ; 0 - are we connected, or have we been connected to the Internet since bootup? 1- No
#COMMS_DEBUG=1 ; 1 - 1 for debug info and multiple local copies
CNIF #COMMS_DEBUG=1
#TEST_TIME_SYNC=0 ; 1 to test time sync
CEND
#MESSAGE_ARRAY_SIZE=256 ; 256
#INTERNAL_MESSAGE_SIZE=30 ;30
GAME_NAME.s="UDP_Chat" ; "UDP_Chat" Game name (for login)
max_wait=250 ; 250 Time to wait for an acknowledgement (frames)
number_resends=5 ; 5 Number of resends to wait, before disconnecting player
lag_allowance=5 ; 5 Number of frames to add to the current lag, when waiting for an out-of-order packet.
max_number_players=8 ; 8
#ACKNOWLEDGE_PACKET=3
#OFFLINE=0
#ONLINE=1
#ATTEMPTING_TO_CONNECT=1
#SERVER=2
#CLIENT=3
#DISCONNECTED=1
#CONNECTED=2
#CONNECTION_REJECTED=3
#START_GAME=4
#NEW_PLAYER=5
#SYSTEM_MESSAGE=4 ; System message
#HIGH=3 ; High priority Security Message or Comms Debug info
#MEDIUM=2 ; Medium " "
#LOW=1 ; Low " "
#SERVER_NUMBER=1
#GAME_CLOSING_TIMEOUT=1500
#DISCONNECT_TIMEOUT=1500
#CLIENT_SERVER=0
#PEER_TO_PEER=1
#LOGIN_TIMEOUT=6000 ; 2 minutes- timeout for login attempt
#SEND=0
#RECEIVE=1
#NUMBER_TIME_SYNCS=6 ; number of packets sent to sync time
#MIN_NUMBER_OF_SYNCS=#NUMBER_TIME_SYNCS/2 ; minimum no of similar time syncs for correct time
#SERVER_RESYNC=4
#SYNC_ALLOWANCE=5 ; 5 frames- 100ms
#TOTAL_PLAYER_INFOS=50
#NUMBERB=1 ; player info types
#NUMBERW=2
#NUMBERL=3
#STRING=4
#FILENAME=5
#MEMORY_BLOCK=6
#END_OF_CRITICAL_DATA=7
#PLAYER_INFO_BUFFER_SIZE=50
#UNORDERED=0
#ORDERED=1
online=#OFFLINE
my_number=0
player_housekeeping=0
sock.l=-1
security_level=#LOW ; level of security warnings (normally #LOW- show #LOW and higher ie: all)
free_security_message=0
next_security_message=0
system_time.l=0
drop_frame=0
login_timeout=0
time_sync=False
current_synching_player=2
current_synched_player=0
CNIF #COMMS_DEBUG=1
comms_debug_level=#LOW ; level of debug info (normally #LOW- show #LOW and higher ie: all)
free_debug_message=0
next_debug_message=0
CEND
tcp_stack=False
disconnect_timeout=0
mtu=1500
player_info_buffer.l=0
player_info_buffer_size.l=0
new_player=0
send_buffer.l=0
incoming_game_data.l=0
incoming_game_data_status=False
socket_base.l=0
CNIF #TEST_TIME_SYNC=1
temp_no=0
CEND
;*************************** UDP Dims *************************
.Dims
INCLUDE "UDPHeader.bb2" ;Standard TCP/UDP library structures and UDP Funcs Newtypes, and Net protocol constants
Dim messages.message_status(max_number_players,#MESSAGE_ARRAY_SIZE)
Dim host.sockaddrin(max_number_players), hostlen.w(max_number_players)
Dim players.player_info(max_number_players)
Dim player_honesty(max_number_players,max_number_players)
Dim last_message_number(max_number_players)
Dim free_message(max_number_players)
Dim packet_number.l(max_number_players)
Dim reliable_packet_in.l(max_number_players)
Dim unreliable_packet_out.l(max_number_players)
Dim unreliable_packet_in.l(max_number_players)
Dim comms_debug_message.system_message(#INTERNAL_MESSAGE_SIZE)
Dim security_message.system_message(#INTERNAL_MESSAGE_SIZE)
Dim login_stage(max_number_players)
Dim time_syncs.sync(max_number_players)
Dim player_info.info(#TOTAL_PLAYER_INFOS)
DEFTYPE .sockaddrin temphost
For a=1 To max_number_players ; this array dimension is for the player number who is claiming another is offline
For b=1 To max_number_players ; this dimension is for the player number who is claimed to be offline
player_honesty(a,b)=False ; initialise array
Next
messages(a,0)\ack=True
unreliable_packet_in(a)=-1
Next
;************************ UDP Funcs ***********************
; These are all specific functions for your game to communicate
; over the internet or by modem/null-modem.
.Security_Warning
Statement Security_Warning{text$,level}
SHARED security_level ; security_level= 0 none, 1 all warnings, 2 medium and severe warnings and 3 only severe warnings
SHARED security_message(),free_security_message
If level>=security_level ; only print out security_level warnings if at set security_level level or higher
If level<#SYSTEM_MESSAGE
text$="Warning: " + text$
EndIf
If free_security_message <= #INTERNAL_MESSAGE_SIZE ; if array not full
security_message(free_security_message)\message=text$,level ; add debug message to array
free_security_message+1 ; up index pointer
Else
free_security_message+1
EndIf
EndIf
End Statement
.Read_Security_Warning
Function.s Read_Security_Warning{}
SHARED security_message(),free_security_message
SHARED next_security_message
If next_security_message=free_security_message OR next_security_message>#INTERNAL_MESSAGE_SIZE
If free_security_message>#INTERNAL_MESSAGE_SIZE+1
next_security_message=0
free_security_message=0
lost_messages=free_security_message-#INTERNAL_MESSAGE_SIZE-1
Function Return "Warning: System message array full- have lost " + Str$(lost_messages) + " message(s)!"
Else
next_security_message=0
free_security_message=0
Function Return ""
EndIf
Else
next_security_message+1
Function Return security_message(next_security_message-1)\message
EndIf
End Function
CNIF #COMMS_DEBUG=1
.Comms_Debug
Statement Comms_Debug{text$,level}
SHARED comms_debug_level ; comms_debug= 0 none, 1 all info, 2 medium and high priority info and 3 only high priority info
SHARED comms_debug_message(),free_debug_message
If level>=comms_debug_level ; only print out debug info if at set debug level or higher
If free_debug_message < #INTERNAL_MESSAGE_SIZE ; if array not full
comms_debug_message(free_debug_message)\message=text$,level ; add debug message to array
free_debug_message+1 ; up index pointer
Else
If free_debug_message=#INTERNAL_MESSAGE_SIZE ; if array full- send error message
comms_debug_message(free_debug_message)\message="Comms debug message array full- may lose next message!",#HIGH
free_debug_message+1
EndIf
EndIf
EndIf
End Statement
.Read_Comms_Debug_Messages
Function.s Read_Comms_Debug_Messages{}
SHARED comms_debug_message(),free_debug_message
SHARED next_debug_message
If next_debug_message=free_debug_message OR next_debug_message>#INTERNAL_MESSAGE_SIZE
If free_debug_message>#INTERNAL_MESSAGE_SIZE+1
next_debug_message=0
free_debug_message=0
lost_messages=free_debug_message-#INTERNAL_MESSAGE_SIZE-1
Function Return "Warning: Comms debug message array full- have lost " + Str$(lost_messages) + " message(s)!"
Else
next_debug_message=0
free_debug_message=0
Function Return ""
EndIf
Else
next_debug_message+1
Function Return comms_debug_message(next_debug_message-1)\message
EndIf
End Function
CEND
Function.b NewNTSC {}
lib$="graphics.library"
*gb.GfxBase=OpenLibrary_(&lib$,0)
If *gb
If *gb\DisplayFlags AND #REALLY_PAL Then p.b=0 Else p=-1
CloseLibrary_ *gb
EndIf
Function Return p
End Function
INCLUDE "UDPFuncs.bb2" ; basic UDP socket functions
.Dim_Message_Arrays
Function Dim_Message_Arrays{new_max_number_players}
SHARED online,max_number_players,messages()
SHARED host(),hostlen(),players(),player_honesty()
SHARED unreliable_packet_out.l(),unreliable_packet_in.l()
SHARED reliable_packet_in.l(),last_message_number()
SHARED free_message(),packet_number(),login_stage()
SHARED time_syncs(),player_info_buffer.l,player_info_buffer_size.l
If online=#OFFLINE
max_number_players=new_max_number_players
Dim messages.message_status(max_number_players,#MESSAGE_ARRAY_SIZE)
Dim host.sockaddrin(max_number_players), hostlen.w(max_number_players)
Dim players.player_info(max_number_players)
Dim player_honesty(max_number_players,max_number_players)
Dim last_message_number(max_number_players)
Dim free_message(max_number_players)
Dim packet_number.l(max_number_players)
Dim reliable_packet_in.l(max_number_players)
Dim unreliable_packet_out.l(max_number_players)
Dim unreliable_packet_in.l(max_number_players)
Dim login_stage(max_number_players)
Dim time_syncs.sync(max_number_players)
For a=1 To max_number_players ; this array dimension is for the player number who is claiming another is offline
For b=1 To max_number_players ; this dimension is for the player number who is claimed to be offline
player_honesty(a,b)=False ; initialise array
Next
messages(a,0)\ack=True
unreliable_packet_in(a)=-1
Next
If player_info_buffer>0
a=FreeMem_(player_info_buffer,player_info_buffer_size)
EndIf
player_info_buffer_size.l=(#PLAYER_INFO_BUFFER_SIZE) * max_number_players
player_info_buffer=AllocMem_(player_info_buffer_size,#MEMF_PUBLIC)
If player_info_buffer=0
Security_Warning{"Out of memory for Player Info Buffer",#SYSTEM_MESSAGE}
Function Return False
EndIf
EndIf
Function Return True
End Statement
.Get_Packet_Source ; Check if packet has come from player already logged on.
Function.w Get_Packet_Source{}
SHARED host(),temphost,max_number_players
i=0
exit=0
Repeat ; check for each player (hostname and socket)
i+1
If host(i)\sin_addr\s_addr=temphost\sin_addr\s_addr AND host(i)\sin_port=temphost\sin_port
exit=1
EndIf
If i=max_number_players AND exit=0; if at end of players and no match is found
i=-1
exit=1
EndIf
Until exit=1
Function Return i
End Function
.Get_Ascii_Address ; build a.b.c.d numerical address from long number
Function.s Get_Ascii_Address{address.l}
string_address.l=Inet_NtoA{address} ; get memory address of ASCII string version of host address (a.b.c.d)
If string_address=0
Function Return ""
EndIf
Repeat ; build ASCII host string
letter.b=(Peek.b(string_address))
If letter<>0
temp$=temp$+Chr$(letter)
EndIf
string_address+1
Until letter=0
Function Return temp$
End Function
.Send_Reliable_Message ; this message is checked to see if it has arrived, and resent if not
Statement Send_Reliable_Message{address.l,data_length.w,player,protocol,ordering} ; if no confirmation can be made, link i
SHARED messages(),free_message(),packet_number(),system_time
If protocol=#PEER_TO_PEER ; Send message Peer-To-Peer
send_string.s=RSet$ ("",data_length + 4)
NPokeL &send_string.s,packet_number(player)
a=CopyMem_(address,&send_string.s + 4,data_length)
messages(player,free_message(player))\number=packet_number(player),False,system_time,send_string.s,0,player ; log message
; inmessage array
WriteUDP{&send_string.s,data_length + 4,player} ; send message
packet_number(player)+1 ; set packet number to next free packet number (+1)
free_message(player)+1 ; set next free message to next one
messages(player,free_message(player))\ack=True ; stop resends if all messages have been acknowledged
If free_message(player)=#MESSAGE_ARRAY_SIZE+1 Then free_message(player)=0 ; if packet number >#MESSAGE_ARRAY_SIZE then wr
Else ; Send message Client-Server
EndIf
End Statement
.Send_Unreliable_Message
Statement Send_Unreliable_Message{address.l,data_length.w,player,protocol}
SHARED UNRELIABLE_PACKET.s,unreliable_packet_out(),send_buffer.l
If protocol=#PEER_TO_PEER ; Send message Peer-To-Peer
NPokeL send_buffer,unreliable_packet_out(player)
NPokeB send_buffer+4,$25 ; UNRELIABLE_PACKET.s
a=CopyMem_(address,send_buffer + 5 ,data_length)
unreliable_packet_out(player)+1
WriteUDP{send_buffer,data_length + 5,player}
Else ; Send message Client-Server
EndIf
End Statement
Function New_Player_Info{player,address.l,port.w,start_of_info.l,player_info_length.l}
SHARED players(),player_info_buffer.l,host()
If address=0
address=NPeekL(start_of_info)
port=NPeekW(start_of_info + 4)
start_of_info=start_of_info + 6
info_size.l=player_info_length - 6
Else
info_size.l=player_info_length
EndIf
If Get_Host_By_Address{&address,port,player}=True
ascii_address.s=Get_Ascii_Address{address}
players(player)\status=#ONLINE,ascii_address.s
players(player)\disconnect_requested=False
player_info_start.l=player_info_buffer + (player-1) * #PLAYER_INFO_BUFFER_SIZE
If info_size <= #PLAYER_INFO_BUFFER_SIZE
NPokeL player_info_start,player_info_length ; put length of player info into first 4 bytes of info
a=CopyMem_(start_of_info,player_info_start+4,player_info_length) ; buffer
CNIF #COMMS_DEBUG=1
Else
Comms_Debug{"Player Info Buffer overflowed!!!",#HIGH}
CEND
EndIf
text$="New player at- " + ascii_address.s + " Port: " + Str$(host(player)\sin_port)
Security_Warning{text$,#SYSTEM_MESSAGE}
Else
Security_Warning{"New player at unknown host!",#MEDIUM}
Function Return False
EndIf
Function Return True
End Statement
Function.s Get_My_Player_Info{my_number}
SHARED player_info(),mtu,host()
i=0
packet_size=0
While player_info(i)\info_type>0 AND i<#TOTAL_PLAYER_INFOS AND player_info(i)\info_type<>#END_OF_CRITICAL_DATA
Select player_info(i)\info_type
Case #NUMBERB
packet_size+1
If packet_size < mtu
send$=send$ + Chr$(player_info(i)\numberb)
Else
CNIF #COMMS_DEBUG=1
Comms_Debug{"Player Info Packet too big!",#HIGH}
CEND
Function Return ""
EndIf
Case #NUMBERW
packet_size+2
If packet_size < mtu
send$=send$ + Mki$(player_info(i)\numberw)
Else
CNIF #COMMS_DEBUG=1
Comms_Debug{"Player Info Packet too big!",#HIGH}
CEND
Function Return ""
EndIf
Case #NUMBERL
packet_size+4
If packet_size < mtu
send$=send$ + Mkl$(player_info(i)\numberl)
Else
CNIF #COMMS_DEBUG=1
Comms_Debug{"Player Info Packet too big!",#HIGH}
CEND
Function Return ""
EndIf
Case #STRING
string_length.w=Len(player_info(i)\string)
packet_size + string_length + 2
If packet_size < mtu
send$=send$ + Mki$(string_length) + player_info(i)\string
Else
CNIF #COMMS_DEBUG=1
Comms_Debug{"Player Info Packet too big!",#HIGH}
CEND
Function Return ""
EndIf
Case #MEMORY_BLOCK
packet_size + 4 + player_info(i)\memory_length
If packet_size < mtu
send$=send$ + Mkl$(player_info(i)\memory_length)
For j=player_info(i)\memory_start To player_info(i)\memory_start + player_info(i)\memory_length
send$=send$ + Chr$(NPeekB(j))
Next
Else
CNIF #COMMS_DEBUG=1
Comms_Debug{"Player Info Packet too big!",#HIGH}
CEND
Function Return ""
EndIf
Case #FILENAME
End Select
i+1
Wend
If New_Player_Info{my_number,host(0)\sin_addr\s_addr,host(0)\sin_port,&send$,packet_size}
Function Return send$
Else
Function Return ""
EndIf
End Function
.Initialise_Server
Function Initialise_Server{localport}
; Set up the game so we can act as Server
SHARED online,port_used,my_number,players(),host()
SHARED max_number_players,player_info_buffer.l
If online=#OFFLINE
If Initialise_UDP{localport} ; bind socket to local port
send$=Get_My_Player_Info{1} ; get my player info from array
If send$<>"" ; and save it to the player info
online=#SERVER ; memory area
my_number=#SERVER_NUMBER
players(#SERVER_NUMBER)\status=#ONLINE ; We are now online as Server
Function Return True
Else
Function Return False
EndIf
Else
Security_Warning{"Error in setting up UDP at Port "+ Str$(port_used),#SYSTEM_MESSAGE}
EndIf
Else
Select online
Case #CLIENT
Security_Warning{"Already logged on to a Server!",#SYSTEM_MESSAGE}
Case #SERVER
Security_Warning{"Already acting as a Server!",#SYSTEM_MESSAGE}
Case #ATTEMPTING_TO_CONNECT
Security_Warning{"Already attempting to log on to a Server!",#SYSTEM_MESSAGE}
End Select
EndIf
Function Return False
End Function
.Disconnect_From_Game
Function Disconnect_From_Game{}
; Remove us from the game, and if we're the Server- close down
; the game and take away our ability to act as Server.
SHARED online,players(),max_number_players,my_number
SHARED disconnect_timeout,time_syncs(),login_stage()
SHARED CP_END_GAME.s,CP_REQ_PLAYER_DISCONNECT.s
For i=0 To max_number_players
USEPATH time_syncs(i)
\player_synching=0
\current_sync=0
\average_ping=0
For j=0 To #NUMBER_TIME_SYNCS ; clear time_sync array
time_syncs(i)\ping_start[j]=0
time_syncs(i)\ping_time[j]=0
Next
login_stage(i)=0 ; reset login stage array
Next
Select online
Case #OFFLINE
Function Return True
Case #SERVER ; if we are Server
dummy=0
For i=2 To max_number_players
If players(i)\status=#ONLINE ; send to player if they're online
send$=CP_END_GAME.s
dummy=1
Send_Reliable_Message{&send$,Len(send$),i,#PEER_TO_PEER,#UNORDERED} ; Send string to connected players
EndIf
Next
If dummy=1
Security_Warning{"Telling players Game has ended.",#SYSTEM_MESSAGE}
disconnect_timeout=#DISCONNECT_TIMEOUT
Function Return False
Else
online=#OFFLINE
Function Return True
EndIf
Case #CLIENT ; we are client
send$=CP_REQ_PLAYER_DISCONNECT.s + Mki$(my_number)
Send_Reliable_Message{&send$,Len(send$),#SERVER_NUMBER,#PEER_TO_PEER,#UNORDERED}
Security_Warning{"Telling Server we are disconnecting from Game.",#SYSTEM_MESSAGE}
disconnect_timeout=#DISCONNECT_TIMEOUT
Function Return False
Case #ATTEMPTING_TO_CONNECT ; we are client
send$=CP_REQ_PLAYER_DISCONNECT.s + Mki$(my_number)
Send_Reliable_Message{&send$,Len(send$),#SERVER_NUMBER,#PEER_TO_PEER,#UNORDERED}
Security_Warning{"Telling Server we are disconnecting from Game.",#SYSTEM_MESSAGE}
disconnect_timeout=#DISCONNECT_TIMEOUT
Function Return False
End Select
End Function
.Connect_To_Server
Function Connect_to_Server{host.s,port.w}
SHARED online, CP_REQ_CONNECT.s, GAME_NAME.s, NET_PROTOCOL_VERSION.s
SHARED login_timeout
If online=#OFFLINE
If Initialise_UDP{port} ; bind socket to local port
If Get_Host_By_Name{GTGetString(0,51), GTGetInteger(0,52),1}=True
Security_Warning{"Attempting to connect to Server",#SYSTEM_MESSAGE}
send$=Mkl$(0) + CP_REQ_CONNECT.s + GAME_NAME.s + Chr$(0) + NET_PROTOCOL_VERSION.s ; "0000" is a Pad for packet number
WriteUDP{&send$,Len(send$),1} ; send connection request
login_timeout=#LOGIN_TIMEOUT
online=#ATTEMPTING_TO_CONNECT
Function Return True
Else
Function Return False
EndIf
Else
Function Return False
EndIf
Else
Select online
Case #CLIENT
Security_Warning{"Already logged on to a Server!",#SYSTEM_MESSAGE}
Case #SERVER
Security_Warning{"Already acting as a Server!",#SYSTEM_MESSAGE}
Case #ATTEMPTING_TO_CONNECT
Security_Warning{"Already attempting to log on to a Server!",#SYSTEM_MESSAGE}
End Select
Function Return False
EndIf
End Function
.Find_Next_Message
Statement Find_Next_Message{player}
SHARED last_message_number(),messages(),free_message()
exit=0
Repeat ; find next unacknowledged message in array
last_message_number(player)+1
If last_message_number(player)=#MESSAGE_ARRAY_SIZE+1 Then last_message_number(player)=0
If last_message_number(player)=free_message(player) ; if have got to free_message then there are no messages waiting to be
exit=1
Else
If messages(player,last_message_number(player))\ack=False ; we've found the next unacknowledged message in the array
exit=1
EndIf
EndIf
Until exit=1
End Statement
.Clear_Player_Arrays
Statement Clear_Player_Arrays{player} ; clear player's arrays
SHARED last_message_number(),messages(),free_message(),host()
SHARED player_honesty(),players(),max_number_players
SHARED unreliable_packet_out(),unreliable_packet_in()
SHARED packet_number(),login_stage()
a=last_message_number(player)
Repeat ; clear message array
messages(player,a)\ack=True ; clear unacknowledged messages off message array
If a=free_message(player) Then exit=True
a+1
If a=#MESSAGE_ARRAY_SIZE+1 Then a=0 ; if at end of array, jump to beginning
Until exit=True
last_message_number(player)=0
free_message(player)=0
packet_number(player)=0
host(player)\sin_addr\s_addr=0 ; clear host address array
host(player)\sin_port=0
For a= 1 To max_number_players ; clear player_honesty array
player_honesty(player,a)=False ; clear disconnected player's array
player_honesty(a,player)=False ; clear other player's arrays who have claimed the disconnected player was offline
Next
players(player)\disconnect_requested=False ; reset disconnect request item
players(player)\status=#OFFLINE ; player's status is offline
unreliable_packet_out(player)=0 ; set player's unreliable packet number back to zero
unreliable_packet_in(player)=-1
login_stage(player)=0
End Statement
.Disconnect_Player
Statement Disconnect_Player{player} ; Disconnect Player from game
SHARED players(),online,max_number_players
SHARED CP_REP_PLAYER_DISCONNECTED.s,CP_REQ_PLAYER_DISCONNECT.s
If online=#SERVER ; If we are the Server
dummy=0
Security_Warning{"Player " + Str$(player) + " has disconnected",#SYSTEM_MESSAGE}
For i=2 To max_number_players
If players(i)\status > #OFFLINE ; send to all players if they're online
If i <> player ; check to see if any players are left online
dummy=1
EndIf
send$=CP_REP_PLAYER_DISCONNECTED.s + Mki$(player) ; tell other players
Send_Reliable_Message{&send$,Len(send$),i,#PEER_TO_PEER,#UNORDERED} ; Send string to connected players that player is
EndIf
Next
If dummy=0 ; if no players are left online
CNIF #COMMS_DEBUG=1
Comms_Debug{"All players have disconnected",#MEDIUM}
CEND
EndIf
Clear_Player_Arrays{player} ; clear message array of player's messages
Else ; if we're a client, inform Server that a player can't be contacted
CNIF #COMMS_DEBUG=1
Comms_Debug{"Telling Server we can't contact player!",#MEDIUM}
CEND
send$=CP_REQ_PLAYER_DISCONNECT.s + Mki$(player)
Send_Reliable_Message{&send$,Len(send$),#SERVER_NUMBER,#PEER_TO_PEER,#UNORDERED} ; Send string to Server
EndIf
End Statement
.Resend_Message ; resend a message
Statement Resend_Message{player,message_number}
SHARED messages(),number_resends,online,players()
SHARED max_number_players,system_time
messages(player,message_number)\timestamp=system_time
messages(player,message_number)\resends+1
If messages(player,message_number)\resends>number_resends ; is host not responding? After 5 retries consider link broken.
CNIF #COMMS_DEBUG=1
Comms_Debug{"Host not responding to Packet no: " + Str$(message_number),#HIGH}
CEND
If messages(player,message_number)\player<>#SERVER_NUMBER ; We've lost contact with a Client
If players(player)\disconnect_requested=False ; if haven't already sent a Disconnect req
Disconnect_Player{player} ; send disconnect request to Server
players(player)\disconnect_requested=True ; don't send any more disconnect requests
EndIf ; for that player
Else ; we've lost contact with Server- game over!
online=#OFFLINE
For a= 1 To max_number_players
Clear_Player_Arrays{a}
Next
EndIf
Else
string_length=Len(messages(player,message_number)\message)
WriteUDP{&messages(player,message_number)\message,string_length,player}
CNIF #COMMS_DEBUG=1
Comms_Debug{"Resent Packet no:" + Str$(message_number),#HIGH}
CEND
EndIf
End Statement
.Acknowledge_Packet ; mark message as been sucessfully sent
Function Acknowledge_Packet{ack_packet_number,player}
SHARED last_message_number(),free_message(),messages()
SHARED lag_allowance,players(),system_time
a=last_message_number(player)
exit=-2
Repeat
If messages(player,a)\number=ack_packet_number ; find message in sent messages array
messages(player,a)\ack=True ; note it as being received
players(player)\lag=system_time-messages(player,a)\timestamp ; calculate lag
exit=True
Else
If a=free_message(player) ; in case bad packet number sends it into a loop! It will only check around buffer once.
exit=False
a$="Warning- Invalid Packet number " + Str$(incoming_packet_number)
Security_Warning{ a$ + " from Player " + Str$(player),#MEDIUM}
EndIf
a+1
EndIf
If a=#MESSAGE_ARRAY_SIZE+1 Then a=0 ; if at end of array, jump to beginning
Until exit>-2
If exit=True ; only do if packet has valid packet_number
If a=last_message_number(player) ; if last message unacknowle
Find_Next_Message{player} ; is acknowledged then find next unacknowledged message
Else ; we have lost a packet- resend last packet number!
allowable_lag=players(player)\lag + lag_allowance ; current lag of player
If messages(player,last_message_number)\timestamp-system_time > allowable_lag
text$="Received packet " + Str$(ack_packet_number) + " ACK out of order,from P: " + Str$(player)
Security_Warning{text$ + " resending last packet",#MEDIUM} ; then resend last message
Resend_Message{player,last_message_number} ; if run out of resends- disconnect player
Else
text$="Received packet " + Str$(ack_packet_number) + " ACK out of order,from P: " + Str$(player)
Security_Warning{text$ + "- no resend yet.",#MEDIUM}
EndIf
EndIf
EndIf
Function Return exit
End Function
.Time_Sync ; Sync time with Server/Sync clients time.
Statement Time_Sync{mode,player,sync_reply_number,incoming_packet_number}
SHARED time_sync,time_syncs(),current_synching_player
SHARED max_number_players,system_time.l,players()
CNIF #TEST_TIME_SYNC=1
SHARED temp_no
CEND
SHARED CP_TIME_SYNC.s,CP_TIME_SYNC_ACK.s,CP_CALCULATED_TIME.s
SHARED CP_CALCULATED_TIME_ACK.s
If time_sync<>#SERVER_RESYNC
If mode=#SEND
If time_sync=#SERVER
current_synching_player+1
If current_synching_player > max_number_players
current_synching_player=2
EndIf
USEPATH time_syncs(current_synching_player)
If \player_synching=True
If \current_sync <= #NUMBER_TIME_SYNCS
\ping_start[\current_sync]=system_time
number=\current_sync
CNIF #TEST_TIME_SYNC=1
If temp_no<2
If \current_sync=1 Then number=4
If \current_sync=4
number=1
temp_no+1
EndIf
EndIf
CEND
send$=CP_TIME_SYNC.s + Mki$(number)
CNIF #COMMS_DEBUG=1
Comms_Debug{"Sending Time Sync to Player " + Str$(player) +"- number: "+ Str$(\current_sync),#LOW}
CEND
\current_sync+1
Send_Reliable_Message{&send$,Len(send$),current_synching_player,#PEER_TO_PEER,#UNORDERED}
Else
Statement Return
EndIf
Else
Statement Return
EndIf
Else
EndIf
Else ; receive time syc or time sync ack
If time_sync=#SERVER ; If Server
USEPATH time_syncs(player)
If sync_reply_number <= #NUMBER_TIME_SYNCS
If sync_reply_number=\last_in_order_ping_number
If sync_reply_number < #NUMBER_TIME_SYNCS
\last_in_order_ping_number+1
EndIf
Else
\waiting_for_restart=True
\sync_received[sync_reply_number]=True
CNIF #COMMS_DEBUG=1
Comms_Debug{"Out of order Time Sync to Player: " + Str$(player) + " Waiting for restart of Sync",#MEDIUM}
CEND
EndIf
While \sync_received[\last_in_order_ping_number + 1]=True AND \last_in_order_ping_number < #NUMBER_TIME_SYNCS
\last_in_order_ping_number+1
Wend
If \waiting_for_restart=False
ping.l=system_time - \ping_start[sync_reply_number]
\ping_time[sync_reply_number]=ping
CNIF #COMMS_DEBUG=1
Comms_Debug{"Received Sync Reply no: " + Str$(sync_reply_number) + " from Player: " + Str$(player), #MEDIUM}
CEND
If \average_ping=0
\average_ping=players(player)\lag
EndIf
If ping < \average_ping + #SYNC_ALLOWANCE
If ping > \average_ping - #SYNC_ALLOWANCE
\number_of_similar_pings+1
\average_ping=(\average_ping + ping) / 2
EndIf
EndIf
If sync_reply_number= #NUMBER_TIME_SYNCS
CNIF #TEST_TIME_SYNC=1
If temp_no=2
\number_of_similar_pings=1 ; to test number of similar pings
temp_no=3
EndIf
CEND
If \number_of_similar_pings > #MIN_NUMBER_OF_SYNCS
closest_to_average=0
closest_ping.l=Abs(\average_ping - \ping_time[0])
For i=1 To #NUMBER_TIME_SYNCS
If Abs(\average_ping - \ping_time[i]) < closest_ping
closest_to_average=i
closest_ping=Abs(\average_ping -\ping_time[i])
EndIf
Next
send$=CP_CALCULATED_TIME.s + Mki$(closest_to_average)
send$=send$ + Mkl$(\ping_start[closest_to_average] + \ping_time[closest_to_average] /2 )
Send_Reliable_Message{&send$,Len(send$),player,#PEER_TO_PEER,#UNORDERED}
CNIF #COMMS_DEBUG=1
text$="Sent Calculated Time: " + Str$(\ping_start[closest_to_average] + \ping_time[closest_to_average] /2 )
Comms_Debug{text$ + " to Player " + Str$(player),#MEDIUM}
CEND
Else ; wait for all sync packets to come in and then restart time sync from beginning
\current_sync=0
\average_ping=0
\number_of_similar_pings=0
\last_in_order_ping_number=0
\waiting_for_restart=False
For i=0 To #NUMBER_TIME_SYNCS
\sync_received[i]=False
Next
CNIF #COMMS_DEBUG=1
Comms_Debug{"Not enough similar Pings- Restarting Sync to Player: " + Str$(player),#MEDIUM}
CEND
EndIf
EndIf
Else
If \last_in_order_ping_number=#NUMBER_TIME_SYNCS ; restart time sync from the beginning
\current_sync=0
\average_ping=0
\number_of_similar_pings=0
\last_in_order_ping_number=0
\waiting_for_restart=False
For i=0 To #NUMBER_TIME_SYNCS
\sync_received[i]=False
Next
CNIF #COMMS_DEBUG=1
Comms_Debug{"Restarting Sync to Player: " + Str$(player),#MEDIUM}
CEND
EndIf
EndIf
EndIf
Else ; if Client
If player=#SERVER_NUMBER
USEPATH time_syncs(#SERVER_NUMBER)
If sync_reply_number<= #NUMBER_TIME_SYNCS
\ping_start[sync_reply_number]=system_time
send$=CP_TIME_SYNC_ACK.s + Mki$(sync_reply_number) + Mkl$(incoming_packet_number)
Send_Reliable_Message{&send$,Len(send$),#SERVER_NUMBER,#PEER_TO_PEER,#UNORDERED}
CNIF #COMMS_DEBUG=1
Comms_Debug{"Received Time Sync from Server, number: "+ Str$(sync_reply_number),#LOW}
CEND
EndIf
EndIf
EndIf
EndIf
Else ; Server is resyncing itself from a Client's time
current_synched_player=0
EndIf
End Statement
Statement Send_Player_Info{player_info_from,player_info_to}
SHARED players(),host(),player_info_buffer.l
SHARED CP_REP_PLAYER_INFO.s
If players(player_info_to)\status > #OFFLINE AND players(player_info_from)\status > #OFFLINE
If player_info_from <> player_info_to
send$=CP_REP_PLAYER_INFO.s + Mki$(player_info_from) + Mkl$(host(player_info_from)\sin_addr\s_addr)
send$=send$ + Mki$(host(player_info_from)\sin_port)
player_info_start.l=player_info_buffer.l + (player_info_from-1) * #PLAYER_INFO_BUFFER_SIZE
player_info_length.l=NPeekL(player_info_start)
slength=Len(send$)
text$=LSet$(send$,player_info_length + slength)
a=CopyMem_(player_info_start+4, &text$ +9 ,player_info_length)
Send_Reliable_Message{&text$,Len(text$),player_info_to,#PEER_TO_PEER,#UNORDERED} ; tell new player of others online
EndIf
EndIf ; and give them their info.
End Statement
Function.l Get_Game_Data{}
SHARED incoming_game_data.l,incoming_game_data_status
If incoming_game_data_status=False
Function Return False
Else
incoming_game_data_status=False
Function Return incoming_game_data
EndIf
End Function
.Requested_Connection ; a player is trying to log in to us
Statement Requested_Connection{incoming_buffer.l}
SHARED sock,players(),host(),hostlen(),GAME_NAME.s
SHARED temphost,temphostlen,online,my_number,max_number_players
SHARED CP_REP_ACCEPT.s,CP_REP_REJECT.s
buffer_length=NPeekW(incoming_buffer-2)
If online=#SERVER ; If offline or Server
dummy=4
exit=False
Repeat ; build game name string from incoming request
dummy+1
b$=Chr$(NPeekB(incoming_buffer+dummy))
If b$<>Chr$(0)
c$=c$+b$
Else
exit=True
EndIf
Until exit=True OR dummy=buffer_length
If b$=Chr$(0)
If c$=GAME_NAME.s ; if request is for correct game
protocol=NPeekB(incoming_buffer+dummy+1)
If protocol=#NET_PROTOCOL_VERSION ; check wether using the same protocol
a$="Connection request from "
player=1
exit=0
Repeat ;check if a spare player slot is availiable
player+1
If players(player)\status=#OFFLINE
exit=1
Else
If player=max_number_players
exit=1
player=-1
EndIf
EndIf
Until exit=1
If player>0 ; connection accepted
If Get_Host_By_Address{&temphost\sin_addr\s_addr,temphost\sin_port,player}=False
Security_Warning{Str$(temphost\sin_addr\s_addr) + "- Host not found!",#SYSTEM_MESSAGE}
Statement Return
EndIf
players(player)\status=#ATTEMPTING_TO_CONNECT
temp$=Get_Ascii_Address{host(player)\sin_addr\s_addr}
a$=a$+temp$ + " Port: " + Str$(host(player)\sin_port)
players(player)\ascii_host_string=temp$ ; store it
send$=CP_REP_ACCEPT.s
send$=send$ + Mki$(player) + Mki$(map) ; send connection accepted back to client
players(player)\disconnect_requested=False
Send_Reliable_Message{&send$,Len(send$),player,#PEER_TO_PEER,#UNORDERED}
Security_Warning{a$,#SYSTEM_MESSAGE}
Statement Return
Else
a$="Connection Request rejected- no spare player slot!"
EndIf
Else
a$="Connection Request rejected- Incorrect Protocol: "+Str$(protocol)
EndIf
Else
a$="Connection Request rejected- wrong game name: "+b$
EndIf
Else
a$="Connection Request rejected- Unknown error!"
EndIf
Else
a$="Connection Request rejected- host already logged on as Client"
EndIf
send$=Mkl$(0) + CP_REP_REJECT.s + a$ ; send connection rejected back with reason
WriteUDP{&send$,Len(send$),0} ; reply to sender
Security_Warning{a$,#MEDIUM}
End Statement
.Decode_Packet ; Decode incoming packet and act accordingly
Function Decode_Packet{}
SHARED players(),host(),temphost,online,unreliable_packet_in()
SHARED my_number,player_honesty(),max_number_players
SHARED login_stage(),time_sync,time_syncs(),system_time,mtu
SHARED player_info_buffer.l,player_info_buffer_size.l,player_info()
SHARED new_player,incoming_game_data.l,incoming_game_data_status
SHARED disconnect_timeout
SHARED CP_REQ_PLAYER_DISCONNECT.s,CP_END_GAME_REC.s,REL_PACKET_ACK.s,CP_REP_ACCEPT.s
SHARED CP_GAME_END.s,CP_REP_PLAYER_DISCONNECTED.s,PING_REQUEST.s
SHARED PING_RESPONSE.s,CP_START_GAME.s,CP_START_GAME_ACK.s
SHARED CP_REP_ACCEPT_ACK.s,CP_REP_PLAYER_INFO.s
SHARED CP_CALCULATED_TIME_ACK.s
return_code=False
incoming_buffer.l=ReadUDP{} ; get data from socket
If incoming_buffer<>False ; if there was some data waiting
incoming_packet_number.l=NPeekL(incoming_buffer)
packet_type=NPeekB(incoming_buffer+4) AND $FF ; check buffer for packet type and convert to a word
player=Get_Packet_Source{} ; check to see if packet is from reliable online source
next_select=False
unknown_packet=False ; check to see if valid packet is received
return_message=0
player_known=True
connecting_player=False
If player>0
Select packet_type
Case #CP_REQ_CONNECT ; request to login to Server
a$="Connection Request rejected- host already logged on to Server."
Security_Warning{Str$(player)+ ": " + a$, #HIGH}
send$=Mkl$(0) + CP_REP_REJECT.s + a$ ; send connection rejected back with reason
return_message=#DISCONNECTED
player_known=False
Case #CP_REP_ACCEPT ; We Received confirmation of logon from Server
If player=#SERVER_NUMBER AND online=#ATTEMPTING_TO_CONNECT
my_number=NPeekW(incoming_buffer+5) ; my player number
map.w=NPeekW(incoming_buffer+7)
players(#SERVER_NUMBER)\status=#ONLINE ; Server is now online
Security_Warning{"Connection Accepted",#SYSTEM_MESSAGE}
send$=Get_My_Player_Info{my_number} ; get player info from array
send$=CP_REP_ACCEPT_ACK.s + Mkl$(incoming_packet_number) + send$
If send$<>"" ; and put all info into the player info memory block
Send_Reliable_Message{&send$,Len(send$),player,#PEER_TO_PEER,#UNORDERED}
return_code=#CONNECTED
time_sync=#CLIENT
Else
online=#OFFLINE
EndIf
Else
Security_Warning{"Illegal Reply Accept attempt by player: " + Str$(player),#MEDIUM}
EndIf
Case #CP_REP_ACCEPT_ACK ; Login routine at Server
If login_stage(player)=0 AND players(player)\status=#ATTEMPTING_TO_CONNECT AND online=#SERVER
If Acknowledge_Packet{NPeekL(incoming_buffer+5),player}=True
For i=1 To max_number_players
Send_Player_Info{i,player} ; send to the logging in Player, the other players's info
Next
time_sync=#SERVER
time_syncs(player)\player_synching=True
login_stage(player)=1
next_select=True
CNIF #COMMS_DEBUG=1
Comms_Debug{"Sending New Player other Player's Info, and Starting Time Sync",#MEDIUM}
text$="R " + Str$(incoming_packet_number) + "," + Str$(player) + ": "
Comms_Debug{text$ + " Packet no. " + Str$(incoming_packet_number) + " arrived at destination.",#HIGH}
CEND
return_message=#ACKNOWLEDGE_PACKET
new_player=player ; #CP_REP_PLAYER_INFO
If new_player <= max_number_players ; new_player is a global varibale for Main:
host.l=host(player)\sin_addr\s_addr
If New_Player_Info{new_player,host.l,host(player)\sin_port,incoming_buffer+9,NPeekW(incoming_buffer-2)-9}
return_code=#NEW_PLAYER
EndIf
Else
Security_Warning{"Illegal Player Number from player: " + Str$(player),#HIGH}
EndIf
EndIf
EndIf
Case #CP_REP_REJECT ; Our logon request was rejected by host
If online=#ATTEMPTING_TO_CONNECT AND player=#SERVER_NUMBER
size=NPeekW(incoming_buffer-2)
temp$=LSet$("",size)
a=CopyMem_(incoming_buffer,&temp$,size)
Security_Warning{temp$,#SYSTEM_MESSAGE}
online=#OFFLINE
return_code=#CONNECTION_REJECTED
Else
Security_Warning{"Illegal Reply Reject attempt by player: " + Str$(player),#MEDIUM}
EndIf
Case #CP_START_GAME ; login completed- we can now start game :)
If player=#SERVER_NUMBER AND online=#ATTEMPTING_TO_CONNECT
online=#CLIENT
time_sync=#OFFLINE
;send$=CP_START_GAME_ACK.s
return_message=#ACKNOWLEDGE_PACKET
CNIF #COMMS_DEBUG=1
Comms_Debug{"Received Start Game Message from Server",#MEDIUM}
CEND
return_code=#START_GAME
EndIf
Case #CP_REP_PLAYER_INFO ; Information about new player that has just logged on
If online=#ATTEMPTING_TO_CONNECT OR online=#CLIENT ; if we are a client
If player=#SERVER_NUMBER
new_player=NPeekW(incoming_buffer+5)
If new_player <= max_number_players
If New_Player_Info{new_player,0,0,incoming_buffer+7,NPeekW(incoming_buffer-2)-7}
return_code=#NEW_PLAYER
return_message=#ACKNOWLEDGE_PACKET
EndIf
Else
Security_Warning{"Illegal Player Number from player: " + Str$(player),#HIGH}
EndIf
Else
Security_Warning{"Illegal Player Info Reply from player: " + Str$(player),#HIGH}
EndIf
Else
Security_Warning{"Illegal Player Info Reply from player: " + Str$(player),#HIGH}
EndIf
Case #CP_REQ_PLAYER_DISCONNECT ; Request from client to disconnect
; or inform Server of disconnected player
If online=#SERVER ; only if Server, and from legal player
disconnecting_player=NPeekW(incoming_buffer+5)
If player=disconnecting_player ; if player is leaving game
Disconnect_Player{player}
Else ; Ping suspect player to see if they're still online
If players(disconnecting_player)\status=#ONLINE
player_honesty(player,disconnecting_player)=True ; record which player claims another is offline.
Send_Reliable_Message{&PING_REQUEST.s,1,disconnecting_player,#PEER_TO_PEER,#UNORDERED} ; so we can disco
CNIF #COMMS_DEBUG=1
text$="R " + Str$(incoming_packet_number) + "," + Str$(player) + ": "
text$=text$ + "Player " + Str$(player) + " claims player " + Str$(disconnecting_player)
Comms_Debug{text$ + " has disconnected",#HIGH}
CEND
Else
CNIF #COMMS_DEBUG=1
text$="Warning: Player " + Str$(player) + " says UNCONNECTED PLAYER " + Str$(disconnecting_player)
text$=text$ + " is unreachable."
Comms_Debug{text$,#HIGH}
CEND
EndIf
return_message=#ACKNOWLEDGE_PACKET
EndIf
Else
Security_Warning{"Illegal Player Disconnect Request Packet from player: " + Str$(player), #MEDIUM}
EndIf
Case #CP_REP_PLAYER_DISCONNECTED ; Server has told us a player has disconnected from the game
; - this can be us as well
If player=#SERVER_NUMBER AND online>#OFFLINE ; only if we're a client and message is fro
disconnected_player=NPeekW(incoming_buffer+5)
Clear_Player_Arrays{disconnected_player} ; player is now offline
If disconnected_player=my_number ; my disconnection request has been confirmed by Server
online=#OFFLINE ; go offline
For a= 1 To max_number_players
If players(a)\status=#ONLINE
Clear_Player_Arrays{a}
EndIf
Next
disconnect_timeout=0
Security_Warning{"We are disconnected from the game.",#SYSTEM_MESSAGE}
return_code=#DISCONNECTED
Else
temp$="Player " + Str$(disconnected_player)
Security_Warning{temp$ + " is disconnected from the game.",#SYSTEM_MESSAGE}
EndIf
return_message=#ACKNOWLEDGE_PACKET
Else
Security_Warning{"Illegal Player Disconnected Reply Packet from player: " + Str$(player),#MEDIUM}
EndIf
Case #CP_END_GAME ; Server has ended Game
If player=#SERVER_NUMBER AND online>#OFFLINE ; if message is from Server
send$=CP_END_GAME_REC.s
Send_Reliable_Message{&send$,Len(send$),#SERVER_NUMBER,#PEER_TO_PEER,#UNORDERED}
online=#OFFLINE
return_message=#ACKNOWLEDGE_PACKET
Security_Warning{"Server has shut down game.",#SYSTEM_MESSAGE}
For a= 1 To max_number_players
If players(a)\status=#ONLINE
Clear_Player_Arrays{a}
EndIf
Next
disconnect_timeout=0
return_code=#DISCONNECTED
Else
Security_Warning{"Illegal End Game attempt by player: " + Str$(player),#MEDIUM}
EndIf
Case #CP_END_GAME_REC ; player has confirmed they received the Game End packet
If online=#SERVER
Clear_Player_Arrays{player} ; player is now offline
dummy=0
For i=2 To max_number_players
If players(i)\status=#ONLINE ; check to see if all players are offline
dummy=1
EndIf
Next
If dummy=0 ; if all players are offline
online=#OFFLINE
CNIF #COMMS_DEBUG=1
text$="R " + Str$(incoming_packet_number) + "," + Str$(player) + ": "
Comms_Debug{text$ + "Player " + Str$(player) + " has confirmed game closure.",#HIGH}
CEND
Security_Warning{"All players have confirmed game has shut down.",#SYSTEM_MESSAGE}
return_code=#DISCONNECTED
CNIF #COMMS_DEBUG=1
Else
text$="R " + Str$(incoming_packet_number) + "," + Str$(player) + ": "
Comms_Debug{text$ + "Player " + Str$(player) + " has confirmed game closure.",#HIGH}
CEND
EndIf
return_message=#ACKNOWLEDGE_PACKET
Else
Security_Warning{"Illegal END_GAME_REC packet received from: " + Str$(player),#MEDIUM}
EndIf
Case #CP_TIME_SYNC
If online > #OFFLINE
Time_Sync{#RECEIVE,player,NPeekW(incoming_buffer+5),incoming_packet_number}
CNIF #COMMS_DEBUG=1
;Comms_Debug{"Received Time Sync from Player: " + Str$(player),#MEDIUM}
CEND
Else
EndIf
Case #CP_TIME_SYNC_ACK ; time sync reply
If online > #OFFLINE
If Acknowledge_Packet{NPeekL(incoming_buffer+7),player}=True
Time_Sync{#RECEIVE,player,NPeekW(incoming_buffer+5),0}
CNIF #COMMS_DEBUG=1
text$="R " + Str$(incoming_packet_number) + "," + Str$(player) + ": "
Comms_Debug{text$ + " Packet no. " + Str$(incoming_packet_number) + " arrived at destination.",#HIGH}
Comms_Debug{"Received Time Sync Ack from Player: " + Str$(player),#MEDIUM}
Comms_Debug{"System time is: " + Str$(system_time),#MEDIUM}
CEND
EndIf
return_message=#ACKNOWLEDGE_PACKET
Else
EndIf
Case #CP_CALCULATED_TIME ; Server finalises time
If player=#SERVER_NUMBER AND online > #OFFLINE
time_difference.l=system_time - time_syncs(#SERVER_NUMBER)\ping_start[NPeekW(incoming_buffer+5)]
CNIF #COMMS_DEBUG=1
Comms_Debug{"Sys time " + Str$(system_time),#MEDIUM}
CEND
system_time=NPeekL(incoming_buffer+7) + time_difference
send$=CP_CALCULATED_TIME_ACK.s + Mkl$(incoming_packet_number)
Send_Reliable_Message{&send$,5,#SERVER_NUMBER,#PEER_TO_PEER,#UNORDERED}
time_sync=False
CNIF #COMMS_DEBUG=1
text$="Received Calculated Time from Player " + Str$(player) +" - system time is now: "
Comms_Debug{text$ + Str$(system_time),#MEDIUM}
Comms_Debug{"old time: " + Str$(NPeekL(incoming_buffer+7)),#LOW}
Comms_Debug{"best average: " + Str$(NPeekW(incoming_buffer+5)),#LOW}
text$="Ping_start: "
Comms_Debug{text$ + Str$(time_syncs(#SERVER_NUMBER)\ping_start[NPeekW(incoming_buffer+5)]),#LOW}
CEND
Else
If online > #OFFLINE
Security_Warning{"Calculated time message received while Offline.",#HIGH}
Else
Security_Warning{"Illegal Calculated time message from Player: " + Str$(player),#HIGH}
EndIf
EndIf
Case #CP_CALCULATED_TIME_ACK
If online=#SERVER ; login routine at server
If login_stage(player)=1 AND players(player)\status=#ATTEMPTING_TO_CONNECT
; player's time has been synched so we now can now start game
For i=2 To max_number_players
If players(i)\status > #OFFLINE
Send_Player_Info{player,i} ; tell others players that new player is online
; and give them new players info.
EndIf
Next
Send_Reliable_Message{&CP_START_GAME.s,1,player,#PEER_TO_PEER,#UNORDERED} ; tell new player to start game
players(player)\status=#ONLINE
CNIF #COMMS_DEBUG=1
Comms_Debug{"New Player " + Str$(player) + " has Synched Time and Is Now Online",#HIGH}
CEND
EndIf
EndIf
If Acknowledge_Packet{NPeekL(incoming_buffer+5),player}=True
USEPATH time_syncs(player)
\player_synching=False
\current_sync=0
\average_ping=0
\number_of_similar_pings=0
\last_in_order_ping_number=0
\waiting_for_restart=False
For i=1 To #NUMBER_TIME_SYNCS
\sync_received[i]=False
Next
a=False : i=1
Repeat
i+1
If time_syncs(player)\player_synching=True
a=True
EndIf
Until a=True OR i=max_number_players
If a=False
time_sync=False
EndIf
CNIF #COMMS_DEBUG=1
text$="R " + Str$(incoming_packet_number) + "," + Str$(player) + ": "
Comms_Debug{text$ + " Packet no. " + Str$(incoming_packet_number) + " arrived at destination.",#HIGH}
Comms_Debug{"Received Calculated Time Ack from Player: " + Str$(player),#MEDIUM}
CEND
EndIf
return_message=#ACKNOWLEDGE_PACKET
Case #REL_STRING_END ; basic string message received from a player
If online>#ATTEMPTING_TO_CONNECT
size=NPeekW(incoming_buffer-2)-6
CNIF #COMMS_DEBUG=1
text$="R " + Str$(incoming_packet_number) + "," + Str$(player) + ": "
temp$=LSet$("",size)
a=CopyMem_(incoming_buffer+5,&temp$,size)
Comms_Debug{text$ + temp$,#MEDIUM}
CEND
incoming_game_data_status=True
NPokeW incoming_game_data,size
NPokeW incoming_game_data+2,#REL_STRING_END
NPokeW incoming_game_data+4,player
a=CopyMem_(incoming_buffer+5,incoming_game_data+6,size) ; copy incoming data to user
return_message=#ACKNOWLEDGE_PACKET
EndIf
Case #UNRELIABLE_PACKET ; an unreliable packet has been received- no acknowledgement needed
If online>#ATTEMPTING_TO_CONNECT
If incoming_packet_number > unreliable_packet_in(player) ; lastest unreliable message
size=NPeekW(incoming_buffer-2)-5
CNIF #COMMS_DEBUG=1
text$="RU " + Str$(incoming_packet_number) + "," + Str$(player) + ": "
temp$=LSet$("",size)
a=CopyMem_(incoming_buffer+5,&temp$,size)
Comms_Debug{text$ + temp$,#MEDIUM}
CEND
unreliable_packet_in(player)=incoming_packet_number ; make this packet number the highest number received
incoming_game_data_status=True
NPokeW incoming_game_data,size
NPokeW incoming_game_data+2,#UNRELIABLE_PACKET
NPokeW incoming_game_data+4,player
a=CopyMem_(incoming_buffer+5,incoming_game_data+6,size) ; copy incoming data to user
Else ; if this packet is slow and has got out of order
CNIF #COMMS_DEBUG=1 ; ignore it
text$="RU " + Str$(incoming_packet_number) + "," + Str$(player) + " Out-of-Order: "
size=NPeekW(incoming_buffer-2)-5
temp$=LSet$("",size)
a=CopyMem_(incoming_buffer+5,&temp$,size)
Comms_Debug{text$ + temp$,#MEDIUM}
CEND
EndIf ; interface buffer
EndIf
Case #REL_PACKET_ACK ; a message has been received by a player
If online>#OFFLINE
If Acknowledge_Packet{incoming_packet_number,player}=True
CNIF #COMMS_DEBUG=1
text$="R " + Str$(incoming_packet_number) + "," + Str$(player) + ": "
Comms_Debug{text$ + " Packet no. " + Str$(incoming_packet_number) + " arrived at destination.",#HIGH}
CEND
EndIf
EndIf
Case #PING_REQUEST ; a Ping request has been received
CNIF #COMMS_DEBUG=1
text$="R " + Str$(incoming_packet_number) + "," + Str$(player) + ": "
Comms_Debug{text$ + "Player " + Str$(player) + " has sent a Ping request.",#HIGH}
CEND
If player=#SERVER_NUMBER AND online=#CLIENT
return_message=#ACKNOWLEDGE_PACKET
Send_Reliable_Message{&PING_RESPONSE.s,1,player,#PEER_TO_PEER,#UNORDERED} ; send Ping Response back
Else
Security_Warning{"Illegal PING_REQUEST received from player: " + Str$(player), #MEDIUM}
EndIf
Case #PING_RESPONSE ; Ping response received
If online=#SERVER
CNIF #COMMS_DEBUG=1
text$="R " + Str$(incoming_packet_number) + "," + Str$(player) + ": "
Comms_Debug{text$ + "Player " + Str$(player) + " has sent a Ping response.",#HIGH}
CEND
For a= 1 To max_number_players ; this is to stop players from disconnecting other players illegally
If player_honesty(a,player)=True ; if player loses connection to other player
Disconnect_Player{a} ; Disconnect player who has lost connection to another player
CNIF #COMMS_DEBUG=1
text$="R " + Str$(incoming_packet_number) + "," + Str$(player) + ": "
Comms_Debug{text$ + "Player " + Str$(a) + " has lost connection to player " + Str$(player),#HIGH}
CEND
EndIf
Next
Else
Security_Warning{"Illegal PING_RESPONSE received from player: " + Str$(player), #MEDIUM}
EndIf
Default
unknown_packet=True
End Select
Else ; if player unknown
Requested_Connection{incoming_buffer} ; player is attempting to connect to Server
player_known=False
EndIf
If unknown_packet=True
If player=-1 AND player_known=True ; if from unknown source
temp$="Unknown Source: " + Get_Ascii_Address{temphost\sin_addr\s_addr} + " Port: " + Str$(temphost\sin_port)
Else ; from known source
temp$="Player: " + Str$(player)
EndIf
Security_Warning{"Unknown Packet from " + temp$,#MEDIUM}
Function Return False
Else
If player=-1 AND player_known=True ; if from unknown source
temp$=": " + Get_Ascii_Address{temphost\sin_addr\s_addr} + " Port: " + Str$(temphost\sin_port)
Security_Warning{"Known Packet from Unknown Source" + temp$,#MEDIUM}
Function Return False
EndIf
EndIf
If return_message>0
If return_message=#ACKNOWLEDGE_PACKET ; send packet acknowledgment back
send$=Mkl$(incoming_packet_number) + REL_PACKET_ACK.s ;
EndIf
WriteUDP{&send$,Len(send$),player} ; return a message back if return_message = 1 or 3
EndIf
EndIf
Function Return return_code
End Function
.Comms_Housekeeping
Function Comms_Housekeeping{}
SHARED messages(),last_message_number(),players(),online
SHARED max_wait,max_number_players,disconnect_timeout
SHARED player_housekeeping,system_time,time_sync
return_code=Decode_Packet{} ; find out what was in the packet
player_housekeeping+1
If player_housekeeping=max_number_players+1
player_housekeeping=1
EndIf
If messages(player_housekeeping,last_message_number(player_housekeeping))\ack=False ; only check if there's messages that hav
If system_time>messages(player_housekeeping,last_message_number(player_housekeeping))\timestamp+max_wait ; has it been 5 se
Resend_Message{player_housekeeping,last_message_number(player_housekeeping)} ; if run out of resends- disconnect player
EndIf
EndIf
If disconnect_timeout>0 ; If disconnection timeout reaches
disconnect_timeout-1 ; zero then disconnect the program
If disconnect_timeout=0
online=#OFFLINE ; go offline
For a= 1 To max_number_players
If players(a)\status=#ONLINE
Clear_Player_Arrays{a}
EndIf
Next
my_number=0
Security_Warning{"We are disconnected from the game.",#SYSTEM_MESSAGE}
return_code=#DISCONNECTED
EndIf
EndIf
If time_sync>False
Time_Sync{#SEND,0,0,0} ; check for any Time Synching that needs doing
EndIf
Function Return return_code
End Function
;***************************************************************
;*********************** End of UDP Stuff ********************
;***************************************************************
;***************************************************************
;************************** Game stuff ***********************
;***************************************************************
; Everything below is for UDP_Chat, and is an example of
; putting the UDP_Funcs into your game.
;******************* Game Variables and Constants **************
exit=False
game_closing=0
PORT_NAME.s="UDP_Chat" ; "UDP_Chat" Rexx portname
#LOCALPORT=27272 ; 27272 default local port to send an receive from
#PORT=27272 ; 27272 default destination port to send data to
#RELIABLE=0
#UNRELIABLE=1
print_player.w=1
message_type=#RELIABLE
;************************ Game Dims **************************
Dim pingprintx(max_number_players)
;******************* Game Functions ********************
;
; These Functions are specific to your program, the ones below
; can be used as examples for your game.
.Print_String ; Print a string in window and scroll if necessary
Statement Print_String{text$}
SHARED ypos
If ypos<200
ypos+10
Else
WScroll 10,60,590,220,0,10
EndIf
WLocate 10,ypos
Print text$ ; print string received
End Statement
.Window_Events
Function Window_Events{}
SHARED pingwidth,hostnamey,online,players(),my_number,packet_number()
SHARED game_closing.w,max_number_players,pingprintx(),hostname
SHARED port_used,message_type,unreliable_packet_out(),system_time
SHARED REL_STRING_END.s
exit=False
ev.l=Event ; get window events
Select ev
Case $40 ; if a gadget has been hit
Select GadgetHit
Case51 ; Try to connect to a Server
If Connect_to_Server{GTGetString(0,51), GTGetInteger(0,52)}=True
WLocate 502,4
Print "Bound to: ",port_used
Else
Print_String{"Unable to Initialise UDP"}
EndIf
Case52 ; Port to connect at above Server
If Get_Host_By_Name{GTGetString(0,51), GTGetInteger(0,52),1} : EndIf
Case53 ; Server button- lets our program become the Server
If Initialise_Server{#LOCALPORT}
Print_String {"Bound to " + hostname + " "+ Str$(port_used)}
WLocate 502,4
Print "Bound to: ",port_used
WLocate pingprintx(#SERVER_NUMBER),32
Print "Serv" ; show that we're Server
Print_String{"We are set up as Server."}
Else
Print_String{"Couldn't Initialise Server!"}
EndIf
Case54 ; get name of localhost
a$=Localhost_Name {} ;
WLocate 5+pingwidth+15,hostnamey+3
Print a$
Case 55 ; button 1
Print_String{"Delay program for 1 second"}
VWait 50 ; put in artificial delay of 1 second For testing purposes
Print_String{"Delay Ended"}
Case 56 ; button 2
Print_String{"Delay program for 80 seconds"}
VWait 4000 ; put in artificial delay of 80 seconds for testing purposes- causes you to lose connection
Print_String{"Delay Ended"}
Case 57 ; button 3 ; print system time
Print_String{"Current System Time: " + Str$(system_time)}
Case 61 ; button 7- toggle between sending Reliable and unreliable messages
If message_type=#RELIABLE
message_type=#UNRELIABLE
Print_String{"Send Unreliable messages."}
Else
message_type=#RELIABLE
Print_String{"Send Reliable messages."}
EndIf
Case62 ; button 8- Pause program
Print_String{"PAUSED"}
Repeat
ev.l=WaitEvent
If ev=$40
Select GadgetHit
Case 62
unpause= 1
Print_String{"UNPAUSED"}
End Select
EndIf
Until unpause=1
Case63 ; Disconnect button- disconnects us from the game
If online=#OFFLINE
Print_String{"We're already offline."}
Else
If Disconnect_From_Game{}
Print_String{"Game has ended."}
For i=1 To 8
WLocate pingprintx(i),32
Print " " ; Clear the lag times
Next
EndIf
EndIf
Case64 ; Send string message to connected players
If online>#ATTEMPTING_TO_CONNECT
temp$=GTGetString(0,64)
For i=1 To 8
If players(i)\status=#ONLINE AND i<>my_number ; send to player if they're online and it's not my number :)
If message_type=#RELIABLE
Print_String{"S " + Str$(packet_number(i)) + "," + Str$(i) + ": "+ temp$}
send$=REL_STRING_END.s + temp$ + Chr$(0)
Send_Reliable_Message{&send$,Len(send$),i,#PEER_TO_PEER,#UNORDERED} ; Send string to players reliably
Else
Print_String{"SU " + Str$(unreliable_packet_out(i)+1) + "," + Str$(i) + ": "+ temp$}
Send_Unreliable_Message{&temp$,Len(temp$),i,#PEER_TO_PEER} ; Send string to connected players unreliably
EndIf
EndIf
Next
EndIf
End Select
Case $200 ; if close button pressed
If Disconnect_From_Game{}
exit=True
Print_String{"Program Closing."}
Else
game_closing=#GAME_CLOSING_TIMEOUT
EndIf
End Select
Function Return exit
End Function
; ARexx code
; It seems replyrexxmsg doesn't actually work for sending result strings
; back, use WRITERESULT, then replymsg for when you want to send
; something back to rexx with result
Statement Result_Reply{*msg.RexxMsg,resulterror.l,resultstring$}
*msg\rm_Result1=result1
If ((*msg\rm_Action & #RXFF_RESULT)<>0)&(result1=0)
*msg\rm_Result2=CreateArgstring_(&resultstring$,Len(resultstring$))
Else
*msg\rm_Result2=0
EndIf
ReplyMsg_ *msg
End Statement
.Get_Rexx_Message
Function Get_Rexx_Message{}
SHARED rexxport.l,online
rmsg.l=RexxEvent(rexxport)
If IsRexxMsg(rmsg)=1
rexxline$=GetRexxCommand(rmsg,1)
Print_String {rexxline$}
linepos=Instr(rexxline$," ")
If linepos=0
command$=rexxline$
Else
command$=Left$(rexxline$,linepos-1)
EndIf
Select command$
Case "QUIT"
ReplyRexxMsg rmsg,0,0,""
Function Return True
Case "ISONLINE"
Select online
Case #OFFLINE
Result_Reply{rmsg,0,"Offline"}
Case #ATTEMPTING_TO_CONNECT
Result_Reply{rmsg,0,"Attempting to Connect"}
Case #SERVER
Result_Reply{rmsg,0,"Server"}
Case #CLIENT
Result_Reply{rmsg,0,"Client"}
End Select
Case "CONNECTTOSERVER"
hostname$=Right$(rexxline$,Len(rexxline$)-linepos)
Print_String {hostname$}
If Connect_to_Server{hostname$,#PORT} : EndIf
ScreenToFront_ Peek.l(Addr Screen(0))
WindowToFront_ Peek.l(Addr Window(0))
ReplyRexxMsg rmsg,0,0,""
Default
ReplyRexxMsg rmsg,0,0,""
End Select
EndIf
Function Return False
End Function
.General_Housekeeping
Function General_Housekeeping{}
SHARED game_closing,online,print_player,pingprintx()
SHARED players(),my_number,print_count,max_number_players
exit=False
If Get_Rexx_Message{}=True ; check for any arexx messages
exit=True ; exit if `Quit' received
EndIf
print_count+1
If print_count=50
print_count=1 ; do once per second
print_player+1
If print_player>max_number_players Then print_player=1
If online>#ATTEMPTING_TO_CONNECT AND print_player<>my_number
WLocate pingprintx(print_player),32
If players(print_player)\status=#ONLINE
Format "0000"
Print Str$(players(print_player)\lag) ; print lag onscreen
Format""
Else
Print" "
EndIf
EndIf
EndIf
If game_closing>0 ; if game is shutting down
If online=#OFFLINE
exit=True ; if all players are offline then shutdown
Print_String{"We are now Offline- Closing program."}
Else
If game_closing>=2 ; carry on countdown
game_closing-1
Else ; if countdown reaches 10 seconds then disconnect regardless
exit=True
Print_String{"Emergency Shutdown!- unable to disconnect from Server."}
EndIf
EndIf
EndIf
Repeat
a$=Read_Security_Warning{}
If a$<>""
Print_String{a$}
EndIf
Until a$=""
CNIF #COMMS_DEBUG=1
Repeat
a$=Read_Comms_Debug_Messages{}
If a$<>""
Print_String{a$}
EndIf
Until a$=""
CEND
Function Return exit
End Function
.Exit
Statement Exit{text$}
SHARED rexxport.l,rexxmsg.l
Print_String{text$} ; print error (if any)
ClrInt 5 ; shut down Vblank timer
If rexxport>0 ; if we've successfully opened an Arexx port then close it
DeleteRexxMsg rexxmsg.l
DeleteMsgPort rexxport.l
Print_String{"Rexxport closed"}
EndIf
Close_UDP{} ; close all UDP stuff down
Print_String{"Program exiting"}
Delay_(50)
End ; close program
End Statement
;********************* End of Functions ***********************
Gosub Init_Gui
;************************ Main Loop **************************
.Main
Repeat
WaitTOF_ ; pause a bit to allow prog to multitask nicely, and sync up display
;NPrint system_time
exit=Window_Events{} ; check for input from user
If online>#OFFLINE
a=Comms_Housekeeping{} ; Check for incoming data and do comms housekeeping work.
Select a
Case #CONNECTED ; Server has told us we're online
WLocate pingprintx(my_number)+5,32
Print "Me" ; print our player number - as a Client.
Case #DISCONNECTED ; We're now offline
For i=1 To 8
WLocate pingprintx(i),32
Print " " ; Clear the lag times
Next
If game_closing>0 Then exit=1
Case #CONNECTION_REJECTED ; Our connection attempt was rejected
Case #START_GAME
Print_String{"We have Started Game :)"}
Case #NEW_PLAYER
Print_String{"New Player no: " + Str$(new_player)}
player_info_start.l=player_info_buffer + (new_player-1) * #PLAYER_INFO_BUFFER_SIZE
Print_String{"Player Info size: " + Str$(NPeekL(player_info_start))}
player_info_start + 4
Print_String{"Player's Colour: " + Str$(NPeekW(player_info_start))} ; get player colour
player_info_start + 2
Print_String{"Player's Score: " + Str$(NPeekL(player_info_start))} ; get player score
player_info_start + 4
player_info_length.w=NPeekW(player_info_start) ; get player name
text$=LSet$("",player_info_length)
a=CopyMem_(player_info_start + 2, &text$, player_info_length)
Print_String{"Player's Name: " + text$}
player_info_start + player_info_length + 2
player_info_length.w=NPeekW(player_info_start) ; get player nick
text$=LSet$("",player_info_length)
a=CopyMem_(player_info_start + 2, &text$, player_info_length)
Print_String{"Player's Nick: " + text$}
player_info_start + player_info_length + 2
End Select
EndIf
;***************** Get Incoming Game Data ****************
game_data.l=Get_Game_Data{} ; get incoming game data
If game_data>0
size=NPeekW(game_data) ; get size of data
If NPeekW(game_data+2)=#REL_STRING_END
text$="R " + Str$(NPeekW(game_data+4)) + ": " ; Reliable packet received
Else
text$="RU " + Str$(NPeekW(game_data+4)) + ": " ; UnReliable Packet received
EndIf
temp$=LSet$("",size) ; create temporary string to print it out, the size of the data
a=CopyMem_(game_data + 6,&temp$,size) ; copy data to string
text$=text$ + temp$
Print_String{text$} ; print it out
EndIf
;***********************************************************
If General_Housekeeping{}=True ; Check for rexx messages
exit=True ; and do general housekeeping work.
EndIf
Until exit=True ; shut down if close gadget hit
Exit{""} ; close UDP socket and Rexxport, and free read memory buffer
; END!
;****************************************************************************
.Init_Gui ; setup window and gadgets- note it's a bit hacked from Alvaro Thompson's original code
ypos=40
WBenchToFront_ ; and isn't proportional and completely font sensitive any more :-/
WbToScreen0
DefaultIDCMP $20|$40|$200
*scr.Screen=Peek.l(Addr Screen(0))
*myfont.TextAttr=*scr\Font
fontheight=*myfont\ta_YSize
ad1.l=*myfont\ta_Name
fontname$=Peek$(ad1)
LoadFont 1,fontname$,fontheight,0
portwidth=TextLength_(*scr\RastPort,"Port:",5)+10
numberswidth=TextLength_(*scr\RastPort,"99999",5)+14
serverwidth=TextLength_(*scr\RastPort,"Send To:",8)+10
connectwidth=TextLength_(*scr\RastPort,"Connect",7)+14
disconnectwidth=TextLength_(*scr\RastPort,"Disconnect",10)+14
pingwidth=TextLength_(*scr\RastPort,"Localhost:",11)
delaywidth=TextLength_(*scr\RastPort,"SERVER",8)+10
inputwidth=TextLength_(*scr\RastPort,"Input:",6)+10
firstperson=TextLength_(*scr\RastPort,"1:",2)+10
#SERVERBTN =51
#PORTBTN =52
#BUTTON =53
x=1
y=1
x1=x+(serverwidth*3)+portwidth+numberswidth+9+3+connectwidth+5
If #NO_CONNECTION=0
GTString 0,#SERVERBTN,x+serverwidth,y,serverwidth*2,fontheight+4,"Send To:",1,256,Localhost_Name {}
Else
GTString 0,#SERVERBTN,x+serverwidth,y,serverwidth*2,fontheight+4,"Send To:",1,256,"localhost"
EndIf
GTInteger 0,#PORTBTN,x+(serverwidth*3)+portwidth+3,y,numberswidth,fontheight+4,"Port:",1,#PORT
GTButton 0,#BUTTON,331,y,delaywidth,fontheight+4,"Server",$10
GTButton 0,63,333+delaywidth,y,disconnectwidth,fontheight+4,"Disconnect",$10
y+fontheight+5
hostnamey=y
GTButton 0,54,5,y,pingwidth,fontheight+4,"Localhost:",$10
WinWidth=x+(serverwidth*3)+portwidth+numberswidth+9+3+connectwidth+8+disconnectwidth+8+90
y+fontheight+5
GTButton 0,55,120,y,firstperson,fontheight+4,"1:",$10
GTButton 0,56,180,y,firstperson,fontheight+4,"2:",$10
GTButton 0,57,240,y,firstperson,fontheight+4,"3:",$10
GTButton 0,58,300,y,firstperson,fontheight+4,"4:",$10
GTButton 0,59,360,y,firstperson,fontheight+4,"5:",$10
GTButton 0,60,420,y,firstperson,fontheight+4,"6:",$10
GTButton 0,61,480,y,firstperson,fontheight+4,"7:",$10
GTButton 0,62,540,y,firstperson,fontheight+4,"8:",$10
For i= 1To8
pingprintx(i)=86+ i*60
Next
pingprinty=y
GTString 0,64,50,215,550,fontheight+4,"Send:",1,67,""
WinHeight=y+fontheight+5
;WinX=WBWidth/2-(WinWidth/2)
;WinY=WBHeight/2-(WinHeight/2)
WinTitle$="UDP Chat"
;ScreenTitle$="UDP Send "+Chr$(169)+"1997."
Window 0,0,10,630,245,$0002|$0004|$0008,WinTitle$,1,2
Use Window 0:Activate 0:AttachGTList 0,0:WTitle WinTitle$,ScreenTitle$:Menus Off
WindowOutput0
WindowInput 0
a$=Localhost_Name {} ;
WLocate 5+pingwidth+15,hostnamey+3
Print a$
WLocate 10,y+3
Print"Ping Time-VBL"
SetInt 5 ; start VBlank timer- this can't be in a If - Then Clause!
If NTSC ; Set up for a PAL rate
If drop_frame=6 ; drop every 6th frame on a NTSC (60fps) system to get a PAL 50 fps rate
drop_frame=0
Else
drop_frame+1
system_time.l+1
EndIf
Else
system_time.l+1 ; up the counter every VBL
EndIf
End SetInt
CNIF #COMMS_DEBUG=0
If FindPortnnn_(PORT_NAME.s)
Exit{"UDP_Chat already running!"}
EndIf
CEND
rexxport.l=CreateMsgPort(PORT_NAME.s)
If rexxport=0
Exit{"Unable to open Rexxport!"}
EndIf
rexxmsg.l=CreateRexxMsg(rexxport,"rexx",PORT_NAME.s)
Print_String {"Type in data, and hit return to send."}
;********** This is the individual player data ****************
; these are just examples- they could be anything
player_info(0)\info_type=#NUMBERW ; player's colour
player_info(0)\numberw=6
player_info(1)\info_type=#NUMBERL ; Player's score
player_info(1)\numberl=55555
player_info(2)\info_type=#STRING ; Player's name
player_info(2)\string="Anton Reinauer"
player_info(3)\info_type=#STRING ; Player's nick
player_info(3)\string="`Ants"
player_info(4)\info_type=#END_OF_CRITICAL_DATA
;*************************************************************
Return